package com.inexas.cu.server.pipe;

import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import org.junit.*;
import com.google.gwt.event.shared.GwtEvent.*;
import com.inexas.cu.client.pipe.*;
import com.inexas.cu.server.pipe.ServiceRegistry.*;

public class BuildTestRequestHandlerRegistry {
	private class Grandfather extends AbstractRequest {
        private static final long serialVersionUID = 8129750844761141559L;
	}

	private class Father extends Grandfather {
        private static final long serialVersionUID = -2290466261463065135L;
	}

	private class Child extends Father {
        private static final long serialVersionUID = -139389022323021320L;
	}
	
	private class MyResponse extends AbstractResponse {
        private static final long serialVersionUID = -8433813308913565563L;

		protected MyResponse(AbstractRequest request) {
	        super(request);
        }

		@Override
        protected Type<ResponseHandler<?>> getAssociatedType() {
	        // todo Implement me
	        throw new RuntimeException("How about implementing me?!");
        }
	}

	private ServiceRegistry registry;
	private ServiceProvider activeHandler;
	private ServiceObserver passiveHandler1, passiveHandler2;
	private AbstractRequest grandfather, father, child;
	private MyResponse response;

	@Before
	public void setup() {
		registry = new ServiceRegistry();
		activeHandler = createStrictMock(ServiceProvider.class);
		passiveHandler1 = createStrictMock(ServiceObserver.class);
		passiveHandler2 = createStrictMock(ServiceObserver.class);
		grandfather = new Grandfather();
		father = new Father();
		child = new Child();
		response = new MyResponse(child);
	}

	@Test
	public void registerGrandfatherFireGrandfather() {
		expect(activeHandler.service(grandfather)).andReturn(response);
		replay(activeHandler);
		registry.register(Grandfather.class, activeHandler);
		assertEquals(registry.fire(grandfather), response);
		verify(activeHandler);
	}

	@Test
	public void registerGrandfatherFireFather() {
		expect(activeHandler.service(father)).andReturn(response);
		replay(activeHandler);
		registry.register(Grandfather.class, activeHandler);
		assertEquals(registry.fire(father), response);
		verify(activeHandler);
	}

	@Test
	public void registerGrandfatherFireChild() {
		expect(activeHandler.service(child)).andReturn(response);
		replay(activeHandler);
		registry.register(Grandfather.class, activeHandler);
		assertEquals(registry.fire(child), response);
		verify(activeHandler);
	}

	@Test(expected = InvalidRegistrationException.class)
	public void registerFatherFireGrandfather() {
		replay(activeHandler);
		registry.register(Father.class, activeHandler);
		assertEquals(registry.fire(grandfather), response);
		verify(activeHandler);
	}

	@Test
	public void registerFatherFireFather() {
		expect(activeHandler.service(father)).andReturn(response);
		replay(activeHandler);
		registry.register(Father.class, activeHandler);
		assertEquals(registry.fire(father), response);
		verify(activeHandler);
	}

	@Test
	public void registerFatherFireChild() {
		expect(activeHandler.service(child)).andReturn(response);
		replay(activeHandler);
		registry.register(Father.class, activeHandler);
		assertEquals(registry.fire(child), response);
		verify(activeHandler);
	}

	@Test
	public void registerGrandfatherAndPassivesFireGrandfather() {
		expect(activeHandler.service(grandfather)).andReturn(response);
		replay(activeHandler);
		passiveHandler1.handle(grandfather, response);
		replay(passiveHandler1);
		passiveHandler2.handle(grandfather, response);
		replay(passiveHandler2);

		registry.register(Grandfather.class, activeHandler);
		registry.register(Grandfather.class, passiveHandler1);
		registry.register(Grandfather.class, passiveHandler2);
		assertEquals(registry.fire(grandfather), response);
		verify(activeHandler);
		verify(passiveHandler1);
		verify(passiveHandler2);
	}

	@Test
	public void registerGrandfatherAndPassivesFireChild() {
		expect(activeHandler.service(child)).andReturn(response);
		replay(activeHandler);
		passiveHandler1.handle(child, response);
		replay(passiveHandler1);
		passiveHandler2.handle(child, response);
		replay(passiveHandler2);

		registry.register(Grandfather.class, activeHandler);
		registry.register(Grandfather.class, passiveHandler1);
		registry.register(Grandfather.class, passiveHandler2);
		assertEquals(registry.fire(child), response);
		verify(activeHandler);
		verify(passiveHandler1);
		verify(passiveHandler2);
	}

}
